/**
 * gislin 2017年7月11日
 */
package com.btcode.orm.conver;

import com.btcode.db.result.Row;
import com.btcode.orm.model.FieldValue;
import com.btcode.orm.model.IField;
import com.btcode.orm.model.IModel;
import com.btcode.orm.relation.ex.IRelation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author gislin 2017年7月11日
 */
public class DefaultModelConver implements IModelConver {

    IValueConver valueConver = new DefaultValueConver();

    @Override
    public <T extends IModel> List<T> converToORMModels(List<Row> rows, Class<T> modelClass) {

        List<T> models = new ArrayList<T>();

        for (Row row : rows) {
            T model = converORMModel(row, modelClass);
            models.add(model);
        }
        return models;
    }

    @Override
    public <T extends IModel> T converORMModel(Row row, Class<T> modelClass) {

        return converORMModelHashMap(row, modelClass);
    }

    @Override
    public <T extends IModel> T converORMModelHashMap(HashMap<String, Object> row, Class<T> modelClass) {
        try {
            T model = modelClass.newInstance();

            List<IField> fields = model.getFields();
            for (IField field : fields) {
                Object value = row.get(field.getFieldName());
                value = valueConver.conveToORMValue(field, value);
                model.setFieldValue(field.getFieldName(), value);
            }

            List<IRelation> relations = model.getRelations();

            for (IRelation relation : relations) {
                IModel slaveModel = relation.getSlaveField().getModelClass().newInstance();
                List<IField> slaveFields = slaveModel.getFields();
                String tableName = slaveModel.getTableName();

                List<IModel> slaveModels = null;

                int index = 0;

                while (true) {
                    HashMap<String, Object> item = new HashMap<>();
                    boolean hasValue = false;

                    Object testValue = row.get("relationModelMap[" + tableName + "]");

                    if (testValue != null && testValue.equals(FieldValue.nullValue)) {
                        slaveModels = new ArrayList<>();
                        break;
                    }

                    for (IField field : slaveFields) {
                        String key = "relationModelMap[" + tableName + "][" + index + "][" + field
                            .getFieldName() + "]";
                        Object v = row.get(key);
                        if (v != null) {
                            item.put(field.getFieldName(), v);
                            hasValue = true;
                        }
                    }

                    if (hasValue) {
                        IModel slavemodel = converORMModelHashMap(item, relation.getSlaveField()
                            .getModelClass());

                        if (slaveModels == null) {
                            slaveModels = new ArrayList<>();
                        }

                        slaveModels.add(slavemodel);
                    }
                    else {
                        break;
                    }

                    index++;
                }

                if (slaveModels != null) {
                    model.setRelationModel(tableName, slaveModels);
                }

            }

            return model;

        }
        catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T extends IModel> List<T> converORMModelHashMaps(List<HashMap<String, Object>> rows,
        Class<T> modelClass) {

        try {
            List<T> models = new ArrayList<T>();

            for (HashMap<String, Object> row : rows) {
                T model = converORMModelHashMap(row, modelClass);
                models.add(model);
            }

            return models;

        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T extends IModel> List<T> converORMModelToModels(List<IModel> models, Class<T> modelClass) {

        List<T> result = new ArrayList<T>();

        for (IModel model : models) {
            T resultItem = converORMModelToModel(model, modelClass);
            result.add(resultItem);
        }

        return result;
    }

    @Override
    public <T extends IModel> T converORMModelToModel(IModel model, Class<T> modelClass) {
        @SuppressWarnings("unchecked") HashMap<String, Object> map = (HashMap<String, Object>) model;

        T result = converORMModelHashMap(map, modelClass);

        return result;
    }

}
